package com.utilities.IO;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
import java.util.TreeSet;

import com.utilities.dataStructures.Range;

/**
 * @author Parit Bansal
 * @date May 29, 2010
 */
public class FileUtilities {

	private static Random rand = null;

	public FileUtilities()
	{
		if (rand == null)
		{
			rand = new Random();
		}
	}
	/**
	 * This method searches the specified folder and gives a unique name 
	 * for a new file to be created. Unique name is typically an integer.
	 * @param folderName Folder to search in
	 * @param extension extension of the file. It can also be null
	 * @return Unique name for a new file. It will not include the extension and folderName
	 */
	public static String findFileWithUniqueName(String folderName, String extension)
	{
		try
		{
			File fl = new File(folderName);
			if (fl.exists() && fl.isDirectory())
			{
				String format = folderName + "/%s";
				while(true)
				{
					int number = rand.nextInt();
					if (number > 0)
					{
						if (extension != null)
						{
							fl = new File (String.format(format+".%s",number,extension));
						}
						else
						{
							fl = new File (String.format(format,number));
						}
						if (!fl.exists()) return String.valueOf(number);
					}
				}
			}
			return null;
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	public static boolean copyFile(String sourceFile, String destinationFile, boolean append)
	{
		try
		{
			BufferedReader buff = new BufferedReader(new FileReader(sourceFile));
			FileWriter fw = new FileWriter(destinationFile,append);
			String readLine = buff.readLine();
			while(readLine != null)
			{
				fw.write(readLine + "\n");
				readLine = buff.readLine();
			}
			fw.flush();
			fw.close();
			buff.close();
			return true;
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * @param sourceFolder
	 * @param destinationFolder
	 * @param append
	 * @return
	 */
	public static boolean copyFiles(String sourceFolder, String destinationFolder, boolean append)
	{
		try
		{
			File srcFolder = new File(sourceFolder);
			File destFolder = new File(destinationFolder);
			if (srcFolder.exists() && srcFolder.isDirectory() && destFolder.exists() && destFolder.isDirectory())
			{
				String[] files = srcFolder.list();
				for (String file : files)
				{
					boolean result = false;
					File fl = new File(srcFolder.getAbsoluteFile() + File.separator + file);
					if (fl.isDirectory())
					{
						fl = new File(destFolder.getAbsolutePath() + File.separator + file);
						fl.mkdir();
						result = copyFiles(srcFolder.getAbsolutePath() + File.separator + file,fl.getAbsolutePath(),append);
					}
					else
					{
						System.out.println("copying " + srcFolder + "/" + file + " to " + destFolder + "/" + file);
						result = copyFile(srcFolder + "/" + file, destFolder + "/" + file, append);
					}
					if (!result) return false;
				}
				return true;
			}
			return false;
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * This method recursively deletes a directory
	 * @param folderName The directory to delete
	 * @return true is directory is successfully deleted else false
	 */
	public static boolean cleanFolderRecursively(String folderName, boolean currentFolderToo) {
		try
		{
			File fl = new File(folderName);
			if (fl.exists() && fl.isDirectory())
			{
				File[] files = fl.listFiles();
				for (File file : files)
				{
					if (file.isDirectory())
					{
						if (cleanFolderRecursively(file.getAbsolutePath(),false))
						{
							if (!file.delete()) return false; 
						}
						else
							return false;
					}
					else
					{
						if (!file.delete()) return false;
					}
				}
				if (currentFolderToo)
				{
					return fl.delete();
				}
				return true;
			}
			else
			{
				System.out.append("Folder doesnt exist " + folderName);
				return true;
			}
		}
		catch(Exception e)
		{
			System.out.println("Problem deleting folder " + folderName);
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * @param fileName
	 * @return
	 */
	public static String removeExtension(String fileName)
	{
		return fileName.split("[.]")[0];
	}

	/**
	 * @param fileName
	 * @return
	 */
	public static String getAbstractPath(String fileName)
	{
		int index = fileName.lastIndexOf('/');
		if (index < 0)
			index = fileName.lastIndexOf('\\');
		return fileName.substring(index + 1);
	}

	public static boolean writeToFile(Collection<String> col, String file)
	{
		try
		{
			FileWriter fileWriter = new FileWriter(file);
			for (String str : col)
			{
				fileWriter.write(str + "\n");
			}
			fileWriter.flush();
			fileWriter.close();
			return true;
		}
		catch(Exception e)
		{
			e.printStackTrace();
			return false;
		}
	}

	public static void WriteToFile(ArrayList<Range> list, String fileName) throws IOException 
	{
		PrintWriter pw = new PrintWriter(new FileWriter(fileName));
		for (Range range : list)
		{
			pw.println(range.getLowerLimit() + "\t" + range.getUpperLimit() + "\t" + range.getMetadata());
//			pw.println(range.getMetadata());
		}
		pw.flush();
		pw.close();
	}
	
	public static void WriteToFile(ArrayList<Range> list, String fileName, int field) throws IOException 
	{
		PrintWriter pw = new PrintWriter(new FileWriter(fileName));
		for (Range range : list)
		{
			switch(field)
			{
			case 1:
				pw.println(range.getLowerLimit() + "\t" + range.getUpperLimit());
				break;
			case 2:
				pw.println(range.getMetadata());
				break;
			case 3:
				pw.println(range.getLowerLimit() + "\t" + range.getUpperLimit() + "\t" + range.getMetadata());
				break;
			}
		}
		pw.flush();
		pw.close();
	}
	
	public static ArrayList<Range> readFromFile(String file) throws Exception
	{
		ArrayList<Range> arrayList = new ArrayList<Range>();
		TreeSet<String> genes = new TreeSet<String>();
		BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
		String readLine = bufferedReader.readLine();
		while(readLine != null)
		{
			String[] params = readLine.split("\t");
			if (!genes.contains(params[2].trim()))
			{
				Range range = new Range(Integer.parseInt(params[0]), 
						Integer.parseInt(params[1]), params[2].trim());
				arrayList.add(range);
				genes.add(params[2].trim());
			}
			readLine = bufferedReader.readLine();
		}
		return arrayList;
	}
	
	public static ArrayList<String> readListFromFile(String file) throws Exception
	{
		TreeSet<String> genes = new TreeSet<String>();
		BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
		String readLine = bufferedReader.readLine();
		while(readLine != null)
		{
			genes.add(readLine.trim());
			readLine = bufferedReader.readLine();
		}
		bufferedReader.close();
		return new ArrayList<String>(genes);
	}

} // FileUtilities
